<template>
  <div class="TFileList">
    <t-three-title title="附件列表">
      <template slot="content">
        <div v-if="['detail', 'file'].includes($route.params.type) || ['detail', 'file'].includes(type)">
          <div
            v-for="file in fileList"
            :key="file.attUrl"
            class="mb-[8px] flex w-[360px] flex-row items-center bg-[#FAFBFC]"
          >
            <img :src="require(`@/assets/images/${getIconByFile(file?.originalName || file.name)}.svg`)" />
            <el-tooltip
              effect="dark"
              :content="file.originalName || file.name"
              placement="top"
              :disabled="file.originalName?.length > 22 || file.name?.length > 22 ? false : true"
            >
              <div class="ml-[8px] w-[239px] flex-1 truncate leading-[32px]">
                {{ file.originalName || file.name }}
              </div>
            </el-tooltip>
            <SvgIcon
              v-if="showButtons.includes('download') && file.id"
              name="file_download"
              class="mr-[8px] cursor-pointer text-[16px]"
              @click="handleDownload(file)"
            />
            <SvgIcon
              v-if="showButtons.includes('preview') && file.id && canPreview(file.attUrl)"
              name="file_preview"
              class="mr-[8px] cursor-pointer text-[16px]"
              @click="kkFileView(file.attUrl)"
            />
          </div>
        </div>
        <el-upload
          v-else
          ref="upload"
          action="#"
          :http-request="handleRequest"
          :multiple="true"
          :limit="limit"
          :disabled="disabled"
          :on-exceed="handleExceed"
          :file-list="fileList"
          :auto-upload="true"
          :on-change="handleChange"
          :accept="accept"
          drag
        >
          <i class="el-icon-upload !mt-[30px]"></i>
          <div class="h-[24px] text-[16px] font-normal leading-[24px] text-[#515A6E]">点击或将文件拖拽到这里上传</div>
          <div class="mb-[23px] mt-[4px] text-[14px] leading-[20px] text-[#7E8A9D]">
            <p v-if="accept.length" class="px-[28px]">
              支持上传{{ accept.join("、") }}等格式且不大于<b>{{ size }}</b
              >MB, 最多可上传<b>{{ limit }}</b
              >个附件
            </p>
            <p v-else class="whitespace-pre-line break-all px-[28px]">
              最多可上传{{ limit }}个附件，每个附件限制{{ size }}MB以下,格式不限
            </p>
          </div>
          <div slot="file" slot-scope="{ file }" class="w-full">
            <div class="flex w-[360px] flex-row items-center bg-[#FAFBFC]">
              <span v-if="file?.attUrl" class="el-icon-success mr-[4px]" style="color: #078d5c"></span>
              <span v-if="file?.attUrl" class="mr-[4px] h-[8px] w-[1px] bg-[#E8EAEF]"></span>
              <img :src="require(`@/assets/images/${getIconByFile(file?.originalName || file.name)}.svg`)" />
              <el-tooltip
                effect="dark"
                :content="file.originalName || file.name"
                placement="top"
                :disabled="file.originalName?.length > 22 || file.name?.length > 22 ? false : true"
              >
                <div class="ml-[8px] w-[239px] flex-1 truncate leading-[24px]">
                  {{ file.originalName || file.name }}
                </div>
              </el-tooltip>
              <SvgIcon
                v-if="showButtons.includes('download') && file.id"
                name="file_download"
                class="mr-[8px] cursor-pointer text-[16px]"
                @click="handleDownload(file)"
              />
              <SvgIcon
                v-if="showButtons.includes('preview') && file.id && canPreview(file.attUrl)"
                name="file_preview"
                class="mr-[8px] cursor-pointer text-[16px]"
                @click="kkFileView(file.attUrl)"
              />
              <SvgIcon
                v-if="showButtons.includes('delete') && !disabled"
                name="file_delete"
                class="mr-[8px] cursor-pointer text-[16px]"
                @click="handleRemove(file)"
              />
            </div>
            <!-- 进度条 -->
            <el-progress
              v-show="false"
              :percentage="file.percentage"
              :show-text="false"
              :stroke-width="3"
              style="top: 26px"
            ></el-progress>
          </div>
        </el-upload>
      </template>
    </t-three-title>
  </div>
</template>

<script>
import axios from "axios";
import { clone } from "xe-utils";
import preview from "@/mixin/preview";
import fileIcon from "@/mixin/fileIcon";
import exportBlob from "@/util/exportBlob";
import { systemUploadFile, systemDeleteFile } from "@/api/file";
import { kkFileView, canPreview } from "@/util/kkview";

export default {
  name: "TFileList",
  mixins: [preview, fileIcon],
  model: {
    prop: "value",
    event: "change",
  },
  props: {
    value: {
      type: Array,
      default: () => {
        return [];
      },
    },
    limit: {
      type: [Number, String],
      require: false,
      default: "100",
    },
    // 文件大小多少兆 MB
    size: {
      type: Number,
      default: 200,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * 接受文件类型，默认所有类型
     * 例如 ['jpg', 'png']
     */
    accept: {
      type: String,
      required: false,
      default: "",
    },
    showButtons: {
      type: Array,
      default: () => {
        return ["download", "preview", "delete"];
      },
    },
    placeholder: {
      type: String,
      require: false,
      default: "",
    },
    type: {
      type: String,
      require: false,
      default: "",
    },
    types: {
      type: String,
      require: false,
      default: "",
    },
  },
  data() {
    return {
      // 文件列表
      fileList: [],
    };
  },
  watch: {
    value: {
      handler(newVal, oldVal) {
        if (Array.isArray(this.value) && this.value.length > 0) {
          this.fileList = this.value;
        } else {
          this.fileList = [];
        }
      },
      deep: true,
      immediate: true,
    },
  },
  methods: {
    kkFileView,
    canPreview,
    async handleRemove(file) {
      try {
        await this.$confirm("确定删除此文件?", "操作确认", {
          confirmButtonText: "确 定",
          cancelButtonText: "取 消",
          type: "warning",
        });
        if (file.id) {
          systemDeleteFile({ id: file.id }).then((data) => {
            this.$message.success("删除成功");
            this.fileList = this.fileList.filter((row) => {
              return row.id !== file.id;
            });
            this.onChange();
          });
        } else {
          // 取消请求
          file.cancel(`「${file.name}」已取消上传`);
          const _index = this.fileList.findIndex((row) => {
            return row.uid === file.uid;
          });
          this.fileList.splice(_index, 1);
        }
      } catch {
        this.$message.warning("已取消删除");
      }
    },
    // 文件超出个数限制时
    handleExceed(files, fileList) {
      this.$message.warning(
        `当前限制选择 ${this.limit} 个文件，本次选择了 ${files.length} 个文件，共选择了 ${
          files.length + fileList.length
        } 个文件`,
      );
    },
    handleSuccess(response, file) {
      this.fileList = this.fileList.map((v) => {
        if (v.uid === file.uid) {
          return response;
        }
        return v;
      });
      this.onChange();
    },
    // 返回 false 或者返回 Promise 且被 reject，则停止上传
    beforeUpload(file) {
      const _name = file.name.split(".");
      const fileType = _name[_name.length - 1];
      if (this.accept.length && !this.accept.includes(fileType.toLowerCase())) {
        this.$message.error(`文件「${file.originalName || file.name}」格式错误，无法继续上传`);
        return false;
      }
      if (file.size <= 0) {
        this.$message.error(`文件「${file.originalName || file.name}」内容为空，无法继续上传`);
        return false;
      }
      if (file.size / 1024 / 1024 > this.size) {
        this.$message.error(`文件「${file.originalName || file.name}」大小超过${this.size}MB，无法继续上传`);
        return false;
      }
      return true;
    },
    onChange() {
      const list = clone(this.fileList, true);
      this.$emit("change", list);
    },
    handleDownload(file) {
      exportBlob({ params: { id: file.id } });
    },
    // 自定义上传实现，多文件上传有延迟
    async handleRequest(param) {
      const that = this;
      const { file } = { ...param };
      try {
        const fileItem = {
          name: file.name,
          percentage: 0,
          raw: file,
          size: file.size,
          status: "",
          uid: file.uid,
          // 定义取消请求
          cancel: null,
        };
        this.fileList.push(fileItem);

        const formData = new FormData();
        formData.append("file", param.file);
        try {
          // 上传文件
          const data = await systemUploadFile(formData, {
            onUploadProgress(progress) {
              const percent = Math.floor((progress.loaded / progress.total) * 100);
              fileItem.percentage = percent;
            },
            cancelToken: new axios.CancelToken(function executor(c) {
              fileItem.cancel = c;
            }),
          });
          if (data && data.length) {
            this.handleSuccess(data[0], fileItem);
          }
        } catch {
          console.log("err");
        }
      } catch {
        this.$message.warning("上传失败");
      }
    },
    handleProgress(event, file) {},
    // 取消所有未上传完成的文件，需要关闭弹窗时手动调用
    cancelFile() {
      this.fileList.forEach((file) => {
        if (file.cancel) {
          file.cancel();
        }
      });
    },
    // 验证文件是否上传完成
    validForm() {
      const isOver = this.fileList.every((v) => {
        return v.id;
      });
      if (!isOver) {
        this.$message.error("有文件未上传完成，请等待上传完成");
        return false;
      }
      return true;
    },
  },
};
</script>

<style lang="scss" scoped>
.TFileList {
  :deep(.el-upload-dragger) {
    width: 368px;
  }

  :deep(.el-upload--picture-card) {
    margin-top: 12px;
  }

  :deep(.el-upload-list__item) {
    height: 30px;
    padding: 0;
    margin-right: 24px;
    background: white;
  }
}
</style>
